Calibrate against several LC setups at once (v4.3.0) - #117
Open
RobbinBouwmeester wants to merge 3 commits into
Open
Calibrate against several LC setups at once (v4.3.0)#117RobbinBouwmeester wants to merge 3 commits into
RobbinBouwmeester wants to merge 3 commits into
Conversation
Calibration ranks all 6,543 heads of the multitask model and keeps one, so a gradient that sits between trained setups is described by the closest single one and the rest of the matrix is discarded. MultiHeadRidgeCalibration keeps that ranking, calibrates the 80 best heads individually with SplineTransformerCalibration, and fits a ridge from those calibrated estimates onto the observed retention times. Each head then contributes an estimate already in the unit of the reference and the ridge decides how much to trust it. On the eight PRIDE setups no DeepLC model was trained on it lowered the held-out error on all eight, median 13 % relative to the gradient (0.01248 to 0.01090 MAE/span): 0.7 % on the setup that pools fractions into one run, 7.5 to 17 % on four others, 28 to 38 % on the three where a single head fitted worst, the largest gain on the smallest reference (230 peptidoforms). Fitting is no slower than the current path (median 1.0 s against 2.3 s) because the head ranking is vectorised, and prediction is unchanged since the full matrix is computed anyway. Opt in by passing the calibration; the default is untouched. Calibration gains a uses_all_heads flag, which is what tells core to hand over the whole matrix instead of one column. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
RalfG
requested changes
Aug 28, 2026
RobbinBouwmeester
force-pushed
the
feat/multihead-calibration
branch
from
August 31, 2026 08:57
1cecdc0 to
833dd2b
Compare
…trim exports - Rewrite the MultiHeadRidgeCalibration docstring to describe the class itself, without the history of the single-head path or benchmark results (those live in the changelog and the PR description). - Shorten the uses_all_heads comment. - Move the RidgeCV import to the module head. - Drop MultiHeadRidgeCalibration from the top-level __all__; it stays public as deeplc.calibration.MultiHeadRidgeCalibration. - Add CLAUDE.md with the documentation instructions proposed in the review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…model calibrate() and predict_and_calibrate() now default to MultiHeadRidgeCalibration whenever the model predicts for more than one LC setup; single-task models keep SplineTransformerCalibration. The default is chosen after the reference matrix is predicted, since the head count is only known then. Passing any Calibration instance overrides the default, so the previous behaviour remains one argument away. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Calibration ranks all 6,543 heads of the multitask model and keeps exactly one (
_best_correlating_head), so a gradient that sits between trained setups is described by the closest single setup and the other 6,542 columns are thrown away.MultiHeadRidgeCalibrationkeeps that same ranking, calibrates the 80 best heads individually withSplineTransformerCalibration, and fits a ridge regression from those calibrated estimates onto the observed retention times. Each head contributes an estimate already in the reference's unit; the ridge decides how much to trust each one.This is now the default for multitask models (updated after review):
calibrateandpredict_and_calibrateuseMultiHeadRidgeCalibrationwhenever the model predicts for more than one LC setup, and keepSplineTransformerCalibrationfor single-task models. The previous behaviour is one argument away:Calibration.uses_all_heads(new,Falseeverywhere else) is what tellscalibrate/predict_and_calibrateto hand over the whole(n, n_heads)matrix instead of one column.Result on the eight held-out PRIDE setups (Figure 1b corpus)
Reference and test peptides are disjoint; relative MAE is MAE / observed gradient span. Measured through the public API, not a notebook reimplementation.
8 of 8 improved, median 0.01248 → 0.01090 (13 %). PXD082486 pools several fractions into one run, so its retention times are not a single gradient and nothing helps there; PXD080314 is the wheat-gluten out-of-domain case.
Cost
Not slower than the current path: median calibration fit 2.3 s → 1.0 s, because
_best_correlating_headloops in Python over 6,543 columns withnp.corrcoefper column while the new ranking is vectorised. (That suggests a separate small win: vectorising the existing helper.) Prediction is unchanged — the full matrix is computed either way.How 80 was chosen
A sweep over k = 1, 2, 3, 5, 10, 20, 40, 80, 160, 320, 640, 1280, 2000 on the same corpus: median relative MAE 0.01248 (k=1) → 0.01137 (10) → 0.01090 (80, flat to 320) → 0.01125 (2000). Also compared, and rejected:
The class also never fits more weights than half the reference supports, which matters for the 230-peptidoform case.
Verification
pytest tests: 141 passed, including 12 new tests intests/test_multihead_calibration.py(beats a single head when the target mixes two setups, records the best head, guards on unfitted use and mismatched head counts, 1-D input, weight cap, empty input, and the twocoreintegration paths).ruff check/ruff format --check: clean.docs/source/models.rstupdated.🤖 Generated with Claude Code